package com.tutou.ikgroup.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.tutou.ikgroup.mapper.ChatFriendMapper;
import com.tutou.ikgroup.mapper.ChatMapper;
import com.tutou.ikgroup.pojo.dto.ChatDTO;
import com.tutou.ikgroup.pojo.po.Chatroom;
import com.tutou.ikgroup.pojo.po.Friend;
import com.tutou.ikgroup.pojo.po.Message;
import com.tutou.ikgroup.service.UserChatService;
import com.tutou.ikgroup.util.ChangeType;
import com.tutou.ikgroup.util.UserCheck;
import com.tutou.ikgroup.websocket.ChannelContextUtil;
import com.tutou.ikuser.mapper.UserMapper;
import com.tutou.ikuser.pojo.dto.Result;
import com.tutou.ikuser.pojo.dto.UserDTO;
import com.tutou.ikuser.pojo.po.User;
import com.tutou.ikuser.pojo.vo.RedisUser;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import static com.tutou.ikuser.util.RedisConstants.*;

@Slf4j
@Service
public class UserChatServiceImpl implements UserChatService {

    @Autowired
    private ChatMapper chatMapper;

    @Autowired
    private ChatFriendMapper chatFriendMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private ChannelContextUtil channelContextUtil;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public Result obo(String token, ChatDTO chatDTO) {
        //保存聊天信息
        User user = UserCheck.token(stringRedisTemplate, token);
        if (user == null) {
            return Result.fail("身份已过期~请登录后重试~");
        }
        chatDTO.setSenderId(user.getUserId()).setSenderName(user.getUserName());
        String senderName = chatDTO.getSenderName();
        String senderId = chatDTO.getSenderId();
        String receiverId = chatDTO.getReceiverId();
        chatMapper.saveMessage(chatDTO);
        stringRedisTemplate.opsForZSet()
                .add(CHAT_OBO_KEY + senderId + ":" + receiverId, senderName + "：" + chatDTO.getMessage(),
                        (double) LocalDateTime.now().toEpochSecond(ZoneOffset.UTC) * 1000);
        stringRedisTemplate.expire(CHAT_OBO_KEY + senderId + ":" + receiverId, LOGIN_TOKEN_TTL, TimeUnit.MINUTES);
        stringRedisTemplate.opsForZSet()
                .add(CHAT_OBO_KEY + receiverId + ":" + senderId, senderName + "：" + chatDTO.getMessage(),
                        (double) LocalDateTime.now().toEpochSecond(ZoneOffset.UTC) * 1000);
        stringRedisTemplate.expire(CHAT_OBO_KEY + receiverId + ":" + senderId, LOGIN_TOKEN_TTL, TimeUnit.MINUTES);
        return channelContextUtil.sendMessageOBO(token, chatDTO);
    }

    @Override
    public Result creatChatroom(String token, String chatRoomName) {
        //判断聊群是否存在
        if (chatMapper.existChatroom(chatRoomName) != 0) {
            return Result.fail("该聊群已存在~");
        }
        ChatDTO chatDTO = new ChatDTO();
        //从redis获取信息
        User user = UserCheck.token(stringRedisTemplate, token);
        if (user == null) {
            return Result.fail("身份已过期~请登录后重试~");
        }
        chatDTO.setSenderId(user.getUserId()).getChatroom().setRoomName(chatRoomName);
        //创建群聊
        chatMapper.crateChatroom(chatDTO);
        Chatroom chatroom = chatDTO.getChatroom();
        String chatroomId = chatroom.getChatroomId();
        String roomName = chatroom.getRoomName();
        //创建完聊群后获取群聊id用户发布到聊群频道中
        //chatroom.setChatroomId(chatMapper.getChatroomId(roomName));

        //User user = userMapper.selectUser(chatDTO.getSenderId());
        //存创建聊群信息到信息表
        chatDTO.setMessage(user.getUserName() + "创建了" + roomName + "聊群");
        //将创建聊群信息存入redis(后缀有群id，标记这条信息是群的名字和创建聊群的信息)
        stringRedisTemplate.opsForZSet()
                .add(CHAT_OBM_KEY + chatroomId, roomName,
                        (double) LocalDateTime.now().toEpochSecond(ZoneOffset.UTC) * 1000);
        stringRedisTemplate.opsForZSet()
                .add(CHAT_OBM_KEY + chatroomId + ":" + user.getUserId(), chatDTO.getMessage(),
                        (double) LocalDateTime.now().toEpochSecond(ZoneOffset.UTC) * 1000);
        stringRedisTemplate.expire(CHAT_OBM_KEY + chatroomId, LOGIN_TOKEN_TTL, TimeUnit.MINUTES);
        //作为群主加入群聊用户
        chatMapper.CsaveChatroomMembers(chatDTO);
        //将群id和群主名字存入redis聊群人员
       /* stringRedisTemplate.opsForList().rightPush(CHAT_ROOM_MEMBER_KEY + roomName, chatroomId);
        stringRedisTemplate.opsForList().rightPush(CHAT_ROOM_MEMBER_KEY + roomName, user.getUserName());
        stringRedisTemplate.expire(CHAT_ROOM_MEMBER_KEY + roomName, LOGIN_TOKEN_TTL, TimeUnit.MINUTES);*/
        //设置聊群的id为-5，标记这条信息是创建聊群的信息
        chatroom.setChatroomId("-5");
        chatDTO.setChatroom(chatroom);
        chatMapper.saveMessage(chatDTO);
        chatDTO.getChatroom().setChatroomId(chatroomId);
        return channelContextUtil.creatChatroom(chatDTO);
    }

    @SneakyThrows
    @Override
    public Result inviteUser(String token, ChatDTO chatDTO) {
        //判断用户是否已在群里面
        //从redis获取邀请者信息
        User user = UserCheck.token(stringRedisTemplate, token);
        if (user == null) {
            return Result.fail("身份已过期~请登录后重试~");
        }
        chatDTO.setSenderId(user.getUserId()).setSenderName(user.getUserName());

        //从redis获取被邀请者的信息
        String receiverPhone = chatDTO.getReceiverPhone();
        String receiver = stringRedisTemplate.opsForValue().get(USER_EXIST_KEY + receiverPhone);
        //RedisUser redisUser = BeanUtil.copyProperties(receiver, RedisUser.class);
        String receiverId = null;
        RedisUser redisUser = null;
        if (receiver != null) {
            redisUser = ChangeType.changeTypeStoO(receiver, RedisUser.class);
            receiverId = redisUser.getUserId();
        } else {
            redisUser = new RedisUser(userMapper.selectUser(receiverPhone));
            receiverId = redisUser.getUserId();
            stringRedisTemplate.opsForValue()
                    .set(USER_EXIST_KEY + receiverPhone, new ObjectMapper().writeValueAsString(redisUser));
            stringRedisTemplate.expire(USER_EXIST_KEY + receiverPhone, LOGIN_TOKEN_TTL, TimeUnit.MINUTES);
        }
        chatDTO.setReceiverName(redisUser.getUserName()).setReceiverId(receiverId);
        if (chatMapper.existUserInChatroom(chatDTO) == 0) {
            return invite(chatDTO);
        }
        return Result.fail("用户已加入该群聊~~");
    }

    public Result invite(ChatDTO chatDTO) {
        //获取聊群名字
        String receiverId = chatDTO.getReceiverId();
        Chatroom chatroom = chatDTO.getChatroom();
        String chatroomId = chatroom.getChatroomId();
        String roomName = String
                .valueOf(stringRedisTemplate.opsForZSet().range(CHAT_OBM_KEY + chatroomId, 0, 0))
                .replaceAll("[\\[\\]]", "");
        //保存邀请记录
        chatDTO.setMessage("用户：" + chatDTO.getSenderName() + "邀请用户：" + chatDTO.getReceiverName() + "进入" + roomName + "群聊");
        //邀请别人进群提示信息是发给自己并标记该条信息是群主邀请用户的信息，chatroomId为-3
        chatDTO.setReceiverId(chatDTO.getSenderId()).setChatroom(chatroom.setChatroomId("-3"));
        chatMapper.saveMessage(chatDTO);
        stringRedisTemplate.opsForZSet()
                .add(CHAT_OBM_KEY + chatroomId, chatDTO.getMessage(),
                        (double) LocalDateTime.now().toEpochSecond(ZoneOffset.UTC) * 1000);
        stringRedisTemplate.expire(CHAT_OBM_KEY + chatroomId, LOGIN_TOKEN_TTL, TimeUnit.MINUTES);

        //用户收到邀请，接收者是被邀请用户并标记该条信息是该用户被邀请的信息，chatroomId为-4
        chatDTO.setReceiverId(receiverId).setChatroom(chatroom.setChatroomId("-4"));
        chatMapper.saveMessage(chatDTO);

        /*chatDTO.setMessage("您被" + chatDTO.getSenderName() + "邀请进入" + roomName + "聊群");
        //用户收到邀请，接收者是被邀请用户并标记该条信息是该用户被邀请的信息，chatroomId为-4
        chatDTO.setReceiverId(receiverId).setChatroom(chatroom.setChatroomId("-4"));
        chatMapper.saveMessage(chatDTO);
        stringRedisTemplate.opsForZSet()
                .add(CHAT_OBM_KEY + roomName, chatDTO.getMessage(),
                        (double) LocalDateTime.now().toEpochSecond(ZoneOffset.UTC) * 1000);
        stringRedisTemplate.expire(CHAT_OBM_KEY + roomName, LOGIN_TOKEN_TTL, TimeUnit.MINUTES);*/

        //保存被邀请用户进入该群的时间
        stringRedisTemplate.opsForZSet()
                .add(CHAT_OBM_KEY + chatroomId + ":" + receiverId, chatDTO.getMessage(),
                        (double) LocalDateTime.now().toEpochSecond(ZoneOffset.UTC) * 1000);
        stringRedisTemplate.expire(CHAT_OBM_KEY + chatroomId + ":" + receiverId, LOGIN_TOKEN_TTL, TimeUnit.MINUTES);
        log.info(CHAT_OBM_KEY + roomName + ":" + receiverId);
        //List<String> range = stringRedisTemplate.opsForList().range(CHAT_ROOM_MEMBER_KEY + roomName, 0, 1);
        chatDTO.setChatroom(chatroom.setChatroomId(chatroomId));
        //添加聊群用户
        chatMapper.IsaveChatroomMembers(chatDTO);
        return channelContextUtil.inviteUser(chatDTO);
    }


    @Override
    public Result obm(String token, ChatDTO chatDTO) {
        User user = UserCheck.token(stringRedisTemplate, token);
        if (user == null) {
            return Result.fail("身份已过期~请登录后重试~");
        }
        chatDTO.setSenderId(user.getUserId());
        Chatroom chatroom = chatDTO.getChatroom();
        String chatroomId = chatroom.getChatroomId();
        String chatroomName = chatMapper.getChatroomName(chatroom.getChatroomId());
        if (chatroomId == null) {
            return Result.fail("聊群不存在~");
        }
        chatDTO.setChatroom(chatroom.setChatroomId(chatroomId));
        //保存聊天信息
        chatMapper.saveMessage(chatDTO);
        stringRedisTemplate.opsForZSet()
                .add(CHAT_OBM_KEY + chatroomId, chatDTO.getMessage(),
                        (double) LocalDateTime.now().toEpochSecond(ZoneOffset.UTC) * 1000);
        stringRedisTemplate.expire(CHAT_OBM_KEY + chatroom.getRoomName(), LOGIN_TOKEN_TTL, TimeUnit.MINUTES);
        return channelContextUtil.sendMessageChatroom(chatDTO);
    }

    //展示单聊信息
    @SneakyThrows
    @Override
    public Result findOBOMessage(String token, ChatDTO chatDTO) {
        //从redis获取单聊信息
        User user = UserCheck.token(stringRedisTemplate, token);
        if (user == null) {
            return Result.fail("身份已过期~请登录后重试~");
        }
        User receiver = UserCheck.addRedisUser(stringRedisTemplate, chatDTO.getReceiverPhone(), userMapper);
        chatDTO.setReceiverId(receiver.getUserId()).setSenderId(user.getUserId());
        List<String> msgList = stringRedisTemplate.opsForList()
                .range(CHAT_OBO_KEY + user.getUserId() + ":" + receiver.getUserId(), 0, -1);
        List<Message> oboMessage = null;
        if (msgList.size() != 0) {
            oboMessage = ChangeType.changeTypeLtoM(msgList);
        } else {
            oboMessage = chatMapper.findOBOMessage(chatDTO);
            if (oboMessage.size() == 0) {
                return Result.ok("快去聊天吧~");
            }
/*            for (Message message : oboMessage) {
                stringRedisTemplate.opsForList().rightPushAll(CHAT_OBO_KEY + user.getUserId() + ":" + receiver.getUserId(),
                        message.getSenderName() + "：" + message.getContent());
                stringRedisTemplate.expire(CHAT_OBO_KEY + user.getUserId() + ":" + receiver.getUserId(), LOGIN_TOKEN_TTL, TimeUnit.MINUTES);
            }*/
        }
        return Result.ok(oboMessage);
    }

    //展示群聊信息
    @Override
    public Result findOBMMessage(String token, String chatroomId) {
        User user = UserCheck.token(stringRedisTemplate, token);
        if (user == null) {
            return Result.fail("身份已过期~请登录后重试~");
        }
        ChatDTO chatDTO = new ChatDTO();
        //获取群聊名字
        String chatroomName = String
                .valueOf(stringRedisTemplate.opsForZSet().range(CHAT_OBM_KEY + chatroomId, 0, 0))
                .replaceAll("[\\[\\]]", "");
        //从redis获取群聊信息
        chatDTO.setSenderId(user.getUserId()).getChatroom().setRoomName(chatroomName);
        //redis获取用户进入群的时间
        Set<ZSetOperations.TypedTuple<String>> typedTuples = stringRedisTemplate.opsForZSet().rangeWithScores(CHAT_OBM_KEY + chatroomId + ":" + user.getUserId(), 0, 0);
        List<Message> messages = null;
        for (ZSetOperations.TypedTuple<String> typedTuple : typedTuples) {
            double time = typedTuple.getScore();
            double now = (double) (LocalDateTime.now().toEpochSecond(ZoneOffset.UTC) * 1000);
            Set<String> msg = stringRedisTemplate.opsForZSet().rangeByScore(CHAT_OBM_KEY + chatroomId, time, now);
            messages = ChangeType.changeTypeSetToL(msg);
            return Result.ok(messages);
        }
        messages = chatMapper.findOBMMessage(chatDTO);
        return Result.ok(messages);
    }

    @Override
    public Result deleteChatroom(String token, ChatDTO chatDTO) {
        User sender = UserCheck.token(stringRedisTemplate, token);
        if (sender == null) {
            return Result.fail("身份已过期~请登录后重试~");
        }
        String chatroomId = chatDTO.getChatroom().getChatroomId();
        String roomName = chatMapper.getChatroomName(chatroomId);
        //添加聊群已解散的信息
        //TODO 删除数据库以及redis群聊信息
        chatMapper.deleteChatroomMembers(chatroomId);
        chatMapper.deleteChatroomMessage(chatroomId);
        chatMapper.deleteChatroom(chatroomId);
        //保存一条聊群解散的信息
        chatDTO.setMessage("群聊：" + roomName + "已解散");
        chatMapper.saveMessage(chatDTO);
        return channelContextUtil.deleteChatroom(roomName, chatDTO);
    }

    @Override
    public Result exitChatroom(ChatDTO chatDTO) {
        String roomName = chatMapper.getChatroomName(chatDTO.getChatroom().getChatroomId());
        //删除该用户在聊群中的成员信息
        chatMapper.exitChatroom(chatDTO);
        return channelContextUtil.exitChatroom(roomName, chatDTO);
    }

    @Override
    public Result getChatroomMember(String chatroomId) {
        List<User> chatroomMember = chatMapper.getChatroomMember(chatroomId);
        return Result.ok(chatroomMember);
    }

    @Override
    public Result getFriendList(String userId) {
        List<Friend> friendList = chatFriendMapper.getFriendList(userId);
        return Result.ok(friendList);
    }
}
